package com.hb.core.config;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @description:
 * @projectName: zhb-frame-build
 * @author: zhouhaizhi
 * @createTime: 2021/8/26 9:52
 * @version:1.0
 */
@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "redis", name = {"hosts", "password", "scheme"})
public class RedisConfig {

    private static final String REDIS_PREFIX = "redis://";

    private static final String SCHEME_REDIS = "redis";

    private static final String SCHEME_REDIS_CLUSTER = "redis-cluster";

    private static final String SCHEME_REDIS_SENTINEL = "redis-sentinel";

    @Value("${spring.application.name:zhb-frame-build}")
    private String appName;

    @Value("${redis.hosts}")
    private String hosts;

    @Value("${redis.password}")
    private String password;

    @Value("${redis.scheme:redis}")
    private String scheme;

    @Value("${redis.sentinel.masterId:master}")
    private String sentinelMasterId;

    /*
        netty线程池数量
     */
    @Value("${redis.nettyThreads:4}")
    private Integer nettyThreads;

    /*
        线程池数量
     */
    @Value("${redis.threads:4}")
    private Integer threads;

    /*
        主节点的最小保持连接数
     */
    @Value("${redis.masterConnectionMinimumIdleSize:16}")
    private Integer masterConnectionMinimumIdleSize;

    /*
        主节点连接池大小
     */
    @Value("${redis.masterConnectionPoolSize:32}")
    private Integer masterConnectionPoolSize;

    /*
        从节点的最小保持连接数
     */
    @Value("${redis.slaveConnectionMinimumIdleSize:16}")
    private Integer slaveConnectionMinimumIdleSize;

    /*
        从节点连接池大小
     */
    @Value("${redis.slaveConnectionPoolSize:32}")
    private Integer slaveConnectionPoolSize;

    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() {
        log.info(">>>>>>>>>>>> 初始化Redisson配置");
        try {
            Config config = this.getConfig();
            RedissonClient redissonClient = Redisson.create(config);
            return redissonClient;
        } catch (Exception e) {
            log.warn("初始化Redisson出现异常", e);
        }
        return null;
    }

    private Config getConfig() {
        Config config = null;
        if (SCHEME_REDIS_CLUSTER.equalsIgnoreCase(scheme)) {
            config = this.clusterConfig();
        }else if(SCHEME_REDIS_SENTINEL.equals(scheme)){
            config = this.sentinelConfig();
        }else {
            config = this.singleConfig();
        }

        config.setNettyThreads(this.nettyThreads)
                .setThreads(this.threads)
                .setCodec(new JsonJacksonCodec());

        return config;
    }

    /*
        单节点模式配置
     */
    private Config singleConfig() {
        String[] nodes = hosts.split(",");
        Config config = new Config();
        config.useSingleServer()
                .setAddress(REDIS_PREFIX + nodes[0])
                .setPassword(password);

        return config;
    }

    /*
        集群模式配置
     */
    private Config clusterConfig() {
        String[] nodes = hosts.split(",");
        String[] clusterNodes = new String[nodes.length];
        for (int i = 0; i < nodes.length; i++) {
            clusterNodes[i] = REDIS_PREFIX + nodes[i];
        }
        Config config = new Config();
        config.useClusterServers()
                .setScanInterval(2000)
                .addNodeAddress(clusterNodes)
                .setPassword(password)
                .setReadMode(ReadMode.MASTER)
                .setIdleConnectionTimeout(10000)
                .setConnectTimeout(10000)
                .setRetryAttempts(3)
                .setRetryInterval(1500)
                .setKeepAlive(true)
                .setPingConnectionInterval(3000)
                .setClientName(this.appName)
                .setMasterConnectionMinimumIdleSize(this.masterConnectionMinimumIdleSize)
                .setMasterConnectionPoolSize(this.masterConnectionPoolSize)
                .setSlaveConnectionMinimumIdleSize(this.slaveConnectionMinimumIdleSize)
                .setSlaveConnectionPoolSize(this.slaveConnectionPoolSize);

        return config;
    }

    /*
        哨兵模式配置
     */
    private Config sentinelConfig() {
        String[] nodes = hosts.split(",");
        String[] sentinelNodes = new String[nodes.length];
        for (int i = 0; i < nodes.length; i++) {
            sentinelNodes[i] = REDIS_PREFIX + nodes[i];
        }
        Config config = new Config();
        config.useSentinelServers()
                .setScanInterval(2000)
                .addSentinelAddress(sentinelNodes)
                .setPassword(password)
                .setReadMode(ReadMode.MASTER)
                .setIdleConnectionTimeout(10000)
                .setConnectTimeout(10000)
                .setRetryAttempts(3)
                .setRetryInterval(1500)
                .setKeepAlive(true)
                .setPingConnectionInterval(3000)
                .setMasterName(this.sentinelMasterId)
                .setClientName(this.appName)
                .setMasterConnectionMinimumIdleSize(this.masterConnectionMinimumIdleSize)
                .setMasterConnectionPoolSize(this.masterConnectionPoolSize)
                .setSlaveConnectionMinimumIdleSize(this.slaveConnectionMinimumIdleSize)
                .setSlaveConnectionPoolSize(this.slaveConnectionPoolSize);

        return config;
    }

}
